package lewiszlw.sso.server.controller;

import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import lewiszlw.sso.server.constant.Constants;
import lewiszlw.sso.server.entity.AccountEntity;
import lewiszlw.sso.server.entity.OAuthTokenEntity;
import lewiszlw.sso.server.mapper.AccountMapper;
import lewiszlw.sso.server.model.ValidationResult;
import lewiszlw.sso.server.model.req.LoginReq;
import lewiszlw.sso.server.service.AccountService;
import lewiszlw.sso.server.service.OAuthSerivce;
import lewiszlw.sso.server.service.ShipmentService;
import lewiszlw.sso.server.service.SsoService;
import lewiszlw.sso.server.util.WebUtils;
import lewiszlw.sso.server.validator.SsoValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * Desc:
 *
 * @author zhanglinwei02
 * @date 2019-05-23
 */
@RestController
@RequestMapping("/sso")
@Slf4j
public class SsoController {

    @Autowired
    private OAuthSerivce oauthSerivce;

    @Autowired
    private SsoService ssoService;

    @Autowired
    private SsoValidator ssoValidator;

    @Autowired
    private AccountService accountService;

    @Autowired
    private ShipmentService shipmentService;

    @Autowired
    private TimedCache<String,String> timedCache;

    @Autowired
    private AccountMapper accountMapper;

    /**
     * 登录页面
     */
    @RequestMapping(value = "/login")
    public ModelAndView login(@RequestParam(value = "redirect_url", required = false) String redirect_url,
                              @RequestParam(value = "client_id", required = false) String clientId,
                              HttpServletRequest request) {
        log.info("[用户登录] - 入参 -> redirectUrl：{}, 客户端clientId：{}", redirect_url, clientId);
        // 验证redirectUri
        if (!StringUtils.isEmpty(redirect_url) && !WebUtils.isHttpUri(redirect_url)) {
            return new ModelAndView("/error").addObject("error", "redirect_uri不合法");
        }

        // 验证clientId
        if (!StringUtils.isEmpty(clientId) && !ssoValidator.validateClientId(clientId).isPass()) {
            return new ModelAndView("/error").addObject("error", "clientId 不存在");
        }
        // 判断是否已登录
        ValidationResult validationResult = ssoService.validateLogin(request);
        if (validationResult.isPass()) {
            // TODO 判断是否从授权页面跳转过来，是则不带code
            // 已登录，直接生成code进行跳转
            OAuthTokenEntity oAuthTokenEntity = (OAuthTokenEntity) validationResult.getData();
            String code = oauthSerivce.genCode(clientId, oAuthTokenEntity.getUserId());
            // 拼接code到redirect_uri
            redirect_url = WebUtils.joinCodeToRedirectUri(redirect_url, code);
            log.info("[用户登录] - 登录成功 -> 正在重定向到地址redirectUrl：{}, 携带的code：{}", redirect_url, code);
            return new ModelAndView("redirect:" + redirect_url);
        } else {
            log.info("[用户登录] - 未登录 -> 正在重定向到地址redirectUrl：{}, 客户端clientId：{}", redirect_url, clientId);
            // 未登录，展示登录页面让用户登录
            return new ModelAndView("/index")
                    .addObject("redirectUri", redirect_url)
                    .addObject("clientId", clientId);
        }
    }

    /**
     * 登录表单提交验证
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ModelAndView login(@ModelAttribute LoginReq req, HttpServletResponse response) throws IOException {
        log.info("[用户登录] - 入参 -> req：{}", JSON.toJSON(req));
        // 验证账号密码
        ValidationResult validationResult = accountService.validateAccount(req.getUsername(), req.getPassword());
        log.info("[验证账号密码] - 出参 -> req：{}", JSON.toJSON(validationResult));
        if (!validationResult.isPass()) {
            return new ModelAndView("/error").addObject("error", validationResult.getMessage());
        }
        AccountEntity accountEntity = (AccountEntity) validationResult.getData();
        Integer userId = accountEntity.getUserId();

        // 登录成功，种下cookie: access token
        String accessToken = oauthSerivce.applyAccessTokenForLoginSuccess(userId);
        WebUtils.setCookie(response, Constants.SSO_LOGIN_ACCESS_TOKEN_COOKIE_NAME, accessToken, Constants.ACCESS_TOKEN_VALID_TIME, false);

        if (StringUtils.isEmpty(req.getClientId()) || StringUtils.isEmpty(req.getRedirectUri())) {
            //首先先查询用户是否已有免登地址
            if (StringUtils.isNotBlank(accountEntity.getAuthUrl())){
                timedCache.put(accountEntity.getId().toString(),accountEntity.getId().toString(), DateUnit.SECOND.getMillis() * 3600000);
                return new ModelAndView("redirect:" + accountEntity.getAuthUrl());
            }else {
                //调用发货接口和开通租户接口
                Map<String, Object> shipmentMap = ssoService.headPartner(accountEntity.getShipId(), accountEntity.getProductId());
                if (StringUtils.equals((String)shipmentMap.get("code"),"0")){
                    Map<String, Object> tenementMap = ssoService.headOpenPartner(accountEntity.getPartnerId());
                    //调用开通租户接口正常的话直接重定向到免登地址
                    if (StringUtils.equals((String)tenementMap.get("code"),"0")){
                        accountMapper.updateAuthUrl((String) shipmentMap.get("authUrl"),Integer.parseInt((String) shipmentMap.get("openId")));
                        timedCache.put(accountEntity.getId().toString(),accountEntity.getId().toString(), DateUnit.SECOND.getMillis() * 3600000);
                        return new ModelAndView("redirect:" + shipmentMap.get("authUrl"));
                    }
                }
            }
            return new ModelAndView("/login_success");
        } else {
            // 生成code并进行跳转
            String code = oauthSerivce.genCode(req.getClientId(), userId);
            String redirectUri = req.getRedirectUri();
            redirectUri = WebUtils.joinCodeToRedirectUri(redirectUri, code);
            log.info("[用户登录] - 登录成功 -> 正在重定向到地址redirectUrl：{}, 携带的code：{}", redirectUri, code);
            return new ModelAndView("redirect:" + redirectUri);
        }
    }

    /**
     * 登出
     */
    @RequestMapping("/logout")
    public String logout() {
        return "logout";
    }

    /**
     * 注册
     */
    @RequestMapping("/signup")
    public String signup() {
        return "signup";
    }


    /**
     * 有度税智发货接口
     *
     * @return
     */
    @RequestMapping("/partner")
    public Map<String, Object> partner() throws IOException {
        return ssoService.headPartner(1,1);
    }

    /**
     * 有度税智开通租户接口
     *
     * @return
     */
    @RequestMapping("/openPartner")
    public Map<String, Object> openPartner() throws IOException {
        return ssoService.headOpenPartner(1);
    }

}
